/*
 * SURFeatures.h
 * SURFeatures Class
 *
 * author : T. D. Gamage
 Based on the samples provided by OpenCV
 */
#ifdef __CUDACC__
#define CUDA_CALLABLE_MEMBER __host__ __device__
#else
#define CUDA_CALLABLE_MEMBER
#endif 
#pragma once
#include <string>
#include <cv.h>
#include <highgui.h>
#include <vector>
#include "opencv2/gpu/gpu.hpp"
 #include <cuda.h> // to get memory on the device  
//#include <cuda_runtime.h> // to get device count
    #include <tbb/tbb.h>
 #include <cstring>
 #include "Frame.h"
 //#include "SURFeaturesCUDA.cuh"
// define whether to use approximate nearest-neighbor search
#define USE_FLANN
using namespace std;
using namespace cv;
using namespace tbb;

class SURFeatures
{
private:    
    CvMemStorage* storage;
    IplImage* object;
    IplImage* image;
	//vector<int> ptpairs;

public:
	//static CvScalar colors[][] = {{{0,0,255}},{{0,128,255}},{{0,255,255}},{{0,255,0}},{{255,128,0}},{{255,255,0}},{{255,0,0}},{{255,0,255}}, {{255,255,255}} };
	//static CvScalar colors[] = (((0,0,255)),((0,128,255)),((0,255,255)),((0,255,0)),((255,128,0)),((255,255,0)),((255,0,0)),((255,0,255)), ((255,255,255)) );
	//static CvScalar colors[];
    CvSeq *objectKeypoints;
	CvSeq *objectDescriptors;
    CvSeq *imageKeypoints;
	CvSeq *imageDescriptors;
    CvSURFParams params;  
    
    /*GPU*/
    vector<DMatch> matchesOfTwo;
    //vector<vector<DMatch>> matches;
    cv::gpu::SURF_GPU surfGpu;
    cv::gpu::BruteForceMatcher_GPU< L2<float> > matcher;
    cv::gpu::GpuMat objectKeyPointsGpuMat;
    cv::gpu::GpuMat objectDescriptorsGpuMat;
    cv::gpu::GpuMat imageKeyPointsGpuMat;
    cv::gpu::GpuMat imageDescriptorsGpuMat;
    
    FlannBasedMatcher matcherFB;
    std::vector< DMatch > matchesFB;
    
    vector<KeyPoint> keypointsObject, keypointsImage;
    vector<float> descriptorsObject, descriptorImage;
    
    //int findNoOFKey
    int getKeypointsObjectSize();
    int getKeypointsImageSize();
    int getDescriptorObjectSize();
    int getDescriptorImageSize();
    
    vector<float> getDescriptorsObject();
    vector<float> getDescriptorImage();
	
     /*GPU*/

	CvPoint src_corners[4];
	CvPoint dst_corners[4];
	//CvPoint src_corners[4]= CvPo;
	/*CvPoint* src_corners;
	CvPoint* dst_corners;*/
	SURFeatures(void);
	void setObject(IplImage* object);
	void setImage(IplImage* image);
	void setSrcCorners();

    cv::gpu::GpuMat getObjectKeyPointsGpuMat();
	cv::gpu::GpuMat getObjectDescriptorsGpuMat();
	cv::gpu::GpuMat getImageKeyPointsGpuMat();
	cv::gpu::GpuMat getImageDescriptorsGpuMat();
	
    
	CvSeq* getObjectDescriptors();
	CvSeq* getImageDescriptors();

    void extractSURF(int objectImage);
    void extractSURFGPU(int objectImage);
    void releaseSURFGPU(int objectImage);
    float matchSURFGPU();
    float* matchSURFGPU(vector<IplImage*> imageVector);
    float  matchSURFGPU(IplImage* imageTwo);
   //// string getSerializedSURFFeatures(vector<float> );

    //bool saveToDB(DBConnect* dbConnect);
    
    float dpMatchSURFGPUCPU(vector<float> descriptorsObject,vector<float> descriptorsImage);
   
    //CUDA_CALLABLE_MEMBER void euclideanDistance(float* descriptorsObject,size_t descriptorsObjectSize,float* descriptorImage, size_t descriptorImageSize);

   // void matchSURFCPU();
	void flannFindPairs( vector<int>& ptpairs );
	int locatePlanarObject();
    double compareSURFDescriptors( const float* d1, const float* d2, double best, int length );

    virtual ~SURFeatures(void);
};